1
ช่องว่างด้านประสิทธิภาพ: ทำไมต้องขยายความสามารถของ NumPy?
AI018Lesson 5
00:00

แม้ว่า NumPy จะถูกสร้างขึ้นบนภาษา C แต่ในบางอัลกอริธึมที่ต้องการการคำนวณหนักๆ ก็จะพบกับ กำแพงการเวกเตอร์ไรเซชัน. สิ่งนี้เกิดขึ้นเมื่อความล่าช้าที่ซ่อนอยู่ในธรรมชาติแบบไดนามิกของภาษา Python มากกว่าประโยชน์จากการใช้โครงสร้างระดับสูง

1. ภาษีตัวแปลและกระบวนการบรรจุข้อมูล (Boxing)

ทุกครั้งที่วนลูปใน Python ปกติจะต้องตรวจสอบประเภทแบบไดนามิกและนับจำนวนการอ้างอิง แม้เมื่อใช้สเกลาร์ของ NumPy การ "บรรจุ" ข้อมูลดิบจากภาษา C ลงในวัตถุของ Python ก็ยังสร้างจุดติดขัดขนาดใหญ่สำหรับฟังก์ชันเช่น $\text{logit}(p) = \log(p/(1-p))$ การจัดการกรณีขอบเขต (edge cases) ในภาษา C นั้นเร็วกว่ามาก:

>>> logit(0) -> -inf
>>> logit(1) -> inf
>>> logit(2) -> nan
>>> logit(-2) -> nan

2. การเพิ่มขนาดอาร์เรย์กลาง (Intermediate Array Bloat)

การใช้งานรูปแบบของ NumPy อย่างบริสุทธิ์จะสร้างพื้นที่หน่วยความจำชั่วคราวสำหรับแต่ละการดำเนินการย่อย การขยายความสามารถผ่าน C-API ทำให้สามารถใช้ การรวมเคอร์เนล (Kernel Fusion), โดยที่การแปลง logit จะถูกคำนวณในหนึ่งรอบเดียวโดยไม่มีภาระงานเพิ่มเติมด้านหน่วยความจำ

3. ความสัมพันธ์ทางพื้นที่ (Spatial Dependencies)

การทำงานที่เกี่ยวข้องกับรูปแบบการเข้าถึงเพื่อนบ้าน เช่น แบบจำลอง 2 มิติ:

$$B(I, J) = A(I, J) + (A(I-1, J) + A(I+1, J) + A(I, J-1) + A(I, J+1)) \cdot 0.5D0 + (A(I-1, J-1) + A(I-1, J+1) + A(I+1, J-1) + A(I+1, J+1)) \cdot 0.25D0$$

เป็นเรื่องยากที่จะแสดงผลได้อย่างมีประสิทธิภาพโดยการตัดข้อมูล (slicing) โดยไม่ต้องมีการสำเนาหน่วยความจำซ้ำซ้อน การขยายความสามารถด้วยภาษา C ทำให้สามารถใช้การคำนวณแบบชี้ไปยังตำแหน่งหน่วยความจำโดยตรงที่จัดเรียงให้เหมาะสมกับแคชได้

main.py
TERMINALbash — 80x24
> Ready. Click "Run" to execute.
>